import java.lang.reflect.Constructor;
import java.util.Random;


public class Village {
	private Team8_Player[] players;
	public static void Main(String[] args)
	{
		
	}
	public static MancalaPlayer[] otherPlayers()
	{
		
		String[] playerNames = new String[]{"Group9RL", "group1", "AILearning"};
		MancalaPlayer[] players = new MancalaPlayer[playerNames.length];
		for(int i = 0; i < playerNames.length; i++)
		{
			String player0Name = playerNames[i];
			try {
	            Class<?> cls = Class.forName(player0Name+"_Player");
	            Class partypes[] = new Class[1];
	            partypes[0] = int.class;
	            Constructor ct = cls.getConstructor(partypes);
	            Object arglist[] = new Object[1];
	            arglist[0] = new Integer(0);
	            players[i] = (MancalaPlayer) ct.newInstance(arglist);
	        } catch (Throwable e) {
	            System.err.println(e);
	        }
		}
		
		return players;
		
	}
	
	public Village(Team8_Player[] players)
	{
		this.players = players;
	}
	
	
	public Team8_Player[] runGenerations(int generations) throws Exception
	{
		int generationCount = 0;
		while(generationCount < generations)
		{
			playGames();
			nextGeneration();
			generationCount++;
		}
		
		return players;
	}
	
	public Team8_Player[] returnPlayers() { return players; }
	
	
	private void nextGeneration()
	{
		Team8_Player[] nextGen = new Team8_Player[players.length+1];
		
		int[] roulette = new int[players.length]; //this enables the random roulette
		//algorithm gets a random number between 0 and the max int in roulette
		//if a number is less than or equal to a num at index i but larger than
		//the int at (i-1), then the algorithm will choose the corresponding player
		//at index i in players
		for(int i = 0; i < players.length; i++)
		{
			if (i == 0)
			{
				roulette[i] = players[i].getScore();
			}
			else
			{
				roulette[i] = roulette[i-1] + players[i].getScore();
			}
		}
		
		
		//pass on best values automatically to next generation
		int best = 0;
		int bestScore = 0;
		int second = 0;
		int secondScore = 0;
		for(int i = 0; i < players.length; i++)
		{
			if(players[i].getScore() > secondScore)
			{
				second = i;
				secondScore = players[i].getScore();
				if(secondScore > bestScore)//swap first and second if second > best
				{
					int temp = best;
					best = second;
					second = temp;
					
					temp = bestScore;
					bestScore = secondScore;
					secondScore = temp;
				}
			}
		}
		
		nextGen[0] = players[best]; //TODO: make a resetScore function or create new players so the score doesn't carry over
		nextGen[1] = players[second];
		
		nextGen[0].resetScore();
		nextGen[1].resetScore();
		
		//skip i = 0 and i = 1; those will be the "elites", the top of each generation
		//automatically passed on so we don't lose valuable genetic code.
		int pairs = players.length/2 - 1;
		int count = 1;
		Random random = new Random();
		while(count <= pairs)
		{
			WeightCollection weight1 = null;
			WeightCollection weight2 = null;
			int max = roulette[roulette.length - 1];
			int next = random.nextInt(max);
			for(int i = 0; i < roulette.length; i++)
			{
				if (next < roulette[i])
				{
					weight1 = players[i].returnMyWeights();
					break;
				}
			}
			next = random.nextInt(max);
			for(int i = 0; i < roulette.length; i++)
			{
				if (next < roulette[i])
				{
					weight2 = players[i].returnMyWeights();
					break;
				}
			}
			
			//breed the two weights
			
			WeightCollection[] nextGenWeights = WeightCollection.mingle(weight1, weight2, 5);
			
			//create new players for the new wieghts
			//TODO: get the player number right, is 0 for now but should change.
			
			nextGen[count*2] = new Team8_Player(0, nextGenWeights[0]);
			
			System.out.println("NextGen Index call " + (count*2+1));
			
			System.out.println("NextGen.length: " + nextGen.length);

			nextGen[count*2+1] = new Team8_Player(0, nextGenWeights[1]);
			
			count++;
		}
		
		for(int i = 0; i < players.length; i++)
		{
			players[i] = nextGen[i];
		}
	}
	
	public void playGames() throws Exception
	{
		
		for(int p1 = 0; p1 < players.length; p1++)
		{
			for(int p2 = p1+1; p2 < players.length; p2++)
			{
				if (p1 != p2)
				{
					System.out.println(this.toString());
					System.out.println("player "+p1+" is playing player "+p2);
					play(players[p1], players[p2]);
					play(players[p2], players[p1]);
				}
			}
			MancalaPlayer[] otherPlayers = Village.otherPlayers();
			for(int i = 0; i < players.length; i++)
			{
				playOtherPlayers(players[p1], otherPlayers[i]);
			}
			
			
		}
	}
	
	private void play(Team8_Player p1, Team8_Player p2) throws Exception
	{
		//initialize the variables
		Team8_Player player[] = new Team8_Player[2];
		player[0] = p1;
		player[1] = p2;
		
		player[0].player = 0;
		player[1].player = 1;
		
		MancalaGameState gs = new KalahPieGameState(4);
		
		//play out the game- not completely sure if this works, i just pasted the play function in termgame
		while (!gs.checkEndGame()) {
	            int move = player[gs.CurrentPlayer()].getMove(gs);
	            while (!gs.validMove(move)) {
	                move = player[gs.CurrentPlayer()].getMove(gs);
	            }
	            gs.play(move);
	    }
		
		//Award winning player the points
	    gs.computeFinalScore();
	    if(gs.getScore(0) > gs.getScore(1))
	    {
	    	p1.addWin();
	    	System.out.println("p1 won " + p1.getWeights().getWeight(0) + ", " + p1.getWeights().getWeight(1) + ", " +  p1.getWeights().getWeight(2) + ", " 
	    			+  p1.getWeights().getWeight(3) + ", "  +  p1.getWeights().getWeight(4) + ", " );
	    }
	    else if(gs.getScore(1) > gs.getScore(0))
	    {
	    	p2.addWin();
	    	System.out.println("p2 won"+ p2.getWeights().getWeight(0) + ", " + p2.getWeights().getWeight(1) + ", " +  p2.getWeights().getWeight(2) + ", " 
	    			+  p2.getWeights().getWeight(3) + ", "  +  p2.getWeights().getWeight(4) + ", " );
	    }
	    else
	    {
	    	p1.addDraw();
	    	p2.addDraw();

	    	System.out.println("draw");
	    }
	    
	    	p1.gamesPlayed++;
	    	p2.gamesPlayed++;
	}
	
	private void playOtherPlayers(Team8_Player p1, MancalaPlayer p2) throws Exception
	{
		p1.player = 0;
		//initialize the variables
		MancalaPlayer player[] = new MancalaPlayer[2];
		player[0] = p1;
		player[1] = p2;
		
		
		MancalaGameState gs = new KalahGameState(4);
		
		//play out the game- not completely sure if this works, i just pasted the play function in termgame
		while (!gs.checkEndGame()) {
	            int move = player[gs.CurrentPlayer()].getMove(gs);
	            while (!gs.validMove(move)) {
	                move = player[gs.CurrentPlayer()].getMove(gs);
	            }
	            gs.play(move);
	    }
		
		//Award winning player the points
	    gs.computeFinalScore();
	    if(gs.getScore(0) > gs.getScore(1))
	    {
	    	p1.addWin();
	    	System.out.println("p1 won " + p1.getWeights().getWeight(0) + ", " + p1.getWeights().getWeight(1) + ", " +  p1.getWeights().getWeight(2) + ", " 
	    			+  p1.getWeights().getWeight(3) + ", "  +  p1.getWeights().getWeight(4) + ", " );
	    }
	    else if(gs.getScore(0) == gs.getScore(1))
	    {
	    	p1.addDraw();
	    }
	    
	    p1.gamesPlayed++;
	}
}
